/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is Indigo framework applicatif.
  
  The Initial Developer of the Original Code is
  Olivier Bugalotto (aka Iteratif) <olivier.bugalotto@iteratif.net>.
  Portions created by the Initial Developer are Copyright (C) 2004-2008
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
*/
package indigo.factory
{
	import flash.utils.getDefinitionByName;
	
	import indigo.internal_indigo;
	import indigo.config.IObjectDefinition;
	import indigo.config.Property;
	import indigo.register.IObjectDefinitionRegistry;

	/*
	 mon commentaire
	*/

	use namespace internal_indigo;
	
	/**
	 * La classe <code>SimpleObjectFactory</code> est une fabrique d'objets basee sur le principe d'injection de dependances
	 * tel que nous en parle Martin Fowler dans son article : <a href="http://www.dotnetguru.org/articles/dossiers/ioc/Fowler/IoC.htm">Conteneurs d’Inversion de Contrôle et modèle d'Injection de Dépendance</a> (fr) 
	 * 
	 * <p>
	 * La fabrique IOC propose par le framework indigo est une fabrique d'objets alimentee par
	 * un referentiel de definitions d'objet contruit soit par programmation, soit par un
	 * fichier de configuration XML appele <b>descripteur XML</b> ou alors par votre propre
	 * implementation en creant une classe implementant l'interface <code>IDescriptor</code>
	 * </p>
	 * 
	 * <p>
	 * Pour ceux qui sont interesses sur le sujet, il suffit de voir comment
	 * fonctionne le pattern <a href="http://fr.wikipedia.org/wiki/Fabrique_abstraite_(patron_de_conception)">Fabrique abstraite</a>
	 * </p>
	 * 
	 * @see indigo.descriptors.ObjectDefinitionDescriptor
	 */
	public class SimpleObjectFactory extends AbstractObjectFactory
	{
		/**
		 * Creer un objet <code>SimpleObjectFactory</code> 
		 * @param registry Reference a un referentiel de definitions
		 * 
		 */
		public function SimpleObjectFactory(registry:IObjectDefinitionRegistry)
		{
			super(registry);
		}
		
		/**
		 * Obtenir un objet a partir du nom d'identification de sa definition dans le referentiel.
		 *  
		 * @param name			Identifiant de la definition
		 * @param definition	Reference de la definition d'objet
		 * @return 
		 * 
		 */
		protected override function createObject(name:String, definition:IObjectDefinition):Object {
			// Garantir que toutes les dependances soient existantes
			/*if(definition.dependencies) {
				for each(var n:String in definition.dependencies) {
					getObject(n);
				}
			}*/
			
			var instance:Object = createInstanceObject(name,definition);
			initProperties(instance,definition.properties);
			// TODO: Appel de la methode init-method si elle existe
			if(definition.initMethod)
				instance[definition.initMethod]();
			
			return instance;
		}
		
		/**
		 * Initialisation des proprietes de l'objet a creer.
		 *  
		 * @param instance		Reference de l'objet a initialiser
		 * @param properties	Tableau d'objets <code>Property</code> contenant les valeurs a affecter aux proprietes de l'objet creer
		 * 
		 */
		internal_indigo function initProperties(instance:Object, properties:Array):void {
			var props:Array = properties;
			for each(var property:Property in props) {
				if(register.containsDefinition(property.value.toString())) { // TODO: utilisation d'une classe ReferenceValue
					var ref:Object = getObject(property.value.toString());
					instance[property.name] = ref;
				} else {
					instance[property.name] = property.value;
				}
			}
		}
		
		/**
		 * Creation d'un instance d'objet definit dans la propriete <code>className</code>
		 * d'un objet <code>IObjectDefinition</code>.
		 * 
		 * @param name			Nom d'identification d'une definition dans le referentiel
		 * @param definition	Reference de la definition de l'objet
		 * @return 
		 * 
		 */
		protected function createInstanceObject(name:String, definition:IObjectDefinition):Object {
			var ClassRef:Class = getDefinitionByName(definition.className) as Class;
			var instance:Object = new ClassRef();
			return instance;
		}
	}
}
